package com.elvis.singleton;

/**
 * 双重检查锁机制
 */
public final class ThreadSafeDoubleCheckLocking {

    /**
     * volatile是很有必要的，volatile在这里的作用是防止指令重排
     */
    private static volatile ThreadSafeDoubleCheckLocking instance;

    /**
     * 私有构造器，防止客户端实例化该类
     */
    private ThreadSafeDoubleCheckLocking() {
        // 在一定情况下防止了反射攻击，但是还是存在通过反射创建出多个实例的可能
        if (instance != null) {
            throw new IllegalStateException("Already initialized.");
        }
    }

    /**
     * Public accessor.
     *
     * @return an instance of the class.
     */
    public static ThreadSafeDoubleCheckLocking getInstance() {
        // fixme 谁能解释一下本地变量为啥能提高性能？
        // 本地变量可以提供25%的性能
        // Joshua Bloch "Effective Java, Second Edition", p. 283-284

        ThreadSafeDoubleCheckLocking result = instance;
        // 检查单例是否被初始化了，如果已经被初始化就直接返回
        if (result == null) {
            // 如果没有被初始化，其他线程可能同时在初始化这个实例，所以需要加锁
            synchronized (ThreadSafeDoubleCheckLocking.class) {
                // 再次给本地变量赋值，检查instance是否在当前线程被阻塞的时候已经别其他线程初始化了
                // 如果已经被其他线程初始化了，直接返回初始化的结果
                result = instance;
                if (result == null) {
                    // instance还是没有初始化，我们能够安全的实例化这个单例(没有其他线程能够进入这里)
                    instance = result = new ThreadSafeDoubleCheckLocking();
                }
            }
        }
        return result;
    }
}
